﻿// Fill out your copyright notice in the Description page of Project Settings.


#include "Combat_Game_CPP/Public/Character/PlayerCharacter.h"
#include "EnhancedInputComponent.h"
#include "EnhancedInputSubsystems.h"
#include "Actor/BaseWeapon.h"
#include "Character/EnemyCharacter.h"
#include "GameFramework/CharacterMovementComponent.h" //运动组件的头文件
#include "Combat_Game_CPP/Public/Helper/DebugHelper.h"
#include "Components/CapsuleComponent.h"
#include "Kismet/BlueprintTypeConversions.h"
#include "Kismet/GameplayStatics.h"
#include "Kismet/KismetSystemLibrary.h"
#include "GameMode/CombatGameMode.h"

// Sets default values
APlayerCharacter::APlayerCharacter()
{
	// Set this character to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
	PrimaryActorTick.bCanEverTick = true;

	// 初始化组件
	CameraBoom = CreateDefaultSubobject<USpringArmComponent>("CameraBoom");
	// 这是为了使用Pawn的控制器旋转 来同步摄像头
	CameraBoom->bUsePawnControlRotation = true;
	FollowCamera = CreateDefaultSubobject<UCameraComponent>("FollowCamera");
	CameraBoom->SetupAttachment(RootComponent);
	FollowCamera->SetupAttachment(CameraBoom);
	// 这么设置是为了让控制器的转动不影响角色的转动，只影响摄像机的转动
	bUseControllerRotationYaw = false;
	bUseControllerRotationPitch = false;
	bUseControllerRotationRoll = false;
	// 为了让角色的移动方向与摄像机的方向一致，需要设置以下参数
	/*UCharacterMovementComponent* PawnMovementComponent = GetCharacterMovement();
	PawnMovementComponent->bOrientRotationToMovement = true;*/
	// 让角色根据自己的移动方向改变朝向
	GetCharacterMovement()->bOrientRotationToMovement = true;
	// 游戏视角动 而 角色朝向不动
	GetCharacterMovement()->bUseControllerDesiredRotation = false;
}

// Called when the game starts or when spawn
void APlayerCharacter::BeginPlay()
{
	Super::BeginPlay();
	//增强输入注册
	RegistInputContext();
	//武器生成
	SpawnWeapon();
	// 注入gamemode
	GameMode = Cast<ACombatGameMode>(UGameplayStatics::GetGameMode(GetWorld()));

	Health = 100.0f;
	MaxHealth = 100.0f;
}

// Called every frame
void APlayerCharacter::Tick(float DeltaTime)
{
	Super::Tick(DeltaTime);
}

// Called to bind functionality to input
void APlayerCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
	Super::SetupPlayerInputComponent(PlayerInputComponent);
	if (UEnhancedInputComponent* EnhancedInputComponent = CastChecked<UEnhancedInputComponent>(PlayerInputComponent))
	{
		//触发动作
		EnhancedInputComponent->BindAction(MoveAction, ETriggerEvent::Triggered, this, &APlayerCharacter::Move);
		EnhancedInputComponent->BindAction(LookAction, ETriggerEvent::Triggered, this, &APlayerCharacter::Look);
		EnhancedInputComponent->BindAction(JumpAction, ETriggerEvent::Triggered, this, &APlayerCharacter::JumpFunction);
		//键盘按下和抬起
		EnhancedInputComponent->BindAction(ChangeAttackAction, ETriggerEvent::Started, this,
		                                   &APlayerCharacter::ChangeAttack);
		EnhancedInputComponent->BindAction(ChangeAttackAction, ETriggerEvent::Completed, this,
		                                   &APlayerCharacter::ChangeAttack);
		EnhancedInputComponent->BindAction(PlayAttackAction, ETriggerEvent::Started, this,
		                                   &APlayerCharacter::PlayAttack);
		EnhancedInputComponent->BindAction(GamePauseAction, ETriggerEvent::Started, this, &APlayerCharacter::GamePause);
	}
}


void APlayerCharacter::Move(const FInputActionValue& Value)
{
	FVector2D MoveVector = Value.Get<FVector2D>();
	//Debug::printLog(MoveVector.ToString());

	if (Controller != nullptr)
	{
		const FRotator Rotation = Controller->GetControlRotation();
		// 绕着三维z轴的rotation 得到对应的x y方向
		const FRotator YawRotation(0, Rotation.Yaw, 0);
		// x轴方向是向前
		const FVector ForwardDirection = FRotationMatrix(YawRotation).GetUnitAxis(EAxis::X);
		// y轴方向是向右
		const FVector RightDirection = FRotationMatrix(YawRotation).GetUnitAxis(EAxis::Y);
		// axis2D W键盘表示x D表示y
		AddMovementInput(ForwardDirection, MoveVector.X);
		AddMovementInput(RightDirection, MoveVector.Y);
	}
}

void APlayerCharacter::Look(const FInputActionValue& Value)
{
	FVector2D LookVector = Value.Get<FVector2D>();
	//Debug::printLog(LookVector.ToString());
	if (Controller == nullptr)
	{
		return;
	}
	// axis2D 上下表示y  左右表示x
	//绕着z轴 左右摆动
	AddControllerYawInput(LookVector.X);
	// 绕着y轴 上下摆动
	// 这里要注意摄像头的配置跟随pawn-> @ CameraBoom->bUsePawnControlRotation = true;
	AddControllerPitchInput(-LookVector.Y);
}

void APlayerCharacter::JumpFunction(const FInputActionValue& Value)
{
	bool JumpBool = Value.Get<bool>();
	JumpBool ? Jump() : StopJumping();
}

void APlayerCharacter::ChangeAttack(const FInputActionValue& Value)
{
	// 切换状态的时候不允许移动 卸载和装备动画结束以后动画通知可以移动
	SetMovementMode(MOVE_None);
	UCharacterMovementComponent* CharacterMovementComponent = GetCharacterMovement();
	//Debug::printLog("ChangeAttack----------" + Value.ToString());
	const bool isAttack = Value.Get<bool>();
	IsAttackState_Anim = isAttack;
	// 切换攻击状态 和 普通状态时 判断播放卸载武器的蒙太奇动画


	if (!isAttack)
	{
		PlayMontage(UnEquipMontage);
		// CharacterMovementComponent->bUseControllerDesiredRotation = true;
		// CharacterMovementComponent->bOrientRotationToMovement = false;
	}
	else
	{
		PlayMontage(EquipMontage);
		// 游戏视角动 而 角色朝向不动
		// CharacterMovementComponent->bUseControllerDesiredRotation = false;
		// CharacterMovementComponent->bOrientRotationToMovement = true;
	}
}

void APlayerCharacter::RegistInputContext()
{
	APlayerController* PlayerController = Cast<APlayerController>(GetController());
	if (PlayerController)
	{
		UEnhancedInputLocalPlayerSubsystem* LocalPlayerSubsystem = ULocalPlayer::GetSubsystem<
			UEnhancedInputLocalPlayerSubsystem>(PlayerController->GetLocalPlayer());
		if (LocalPlayerSubsystem)
		{
			LocalPlayerSubsystem->AddMappingContext(InputMappingContext, 0);
		}
	}
}

void APlayerCharacter::SpawnWeapon()
{
	if (SelectWeapon)
	{
		Weapon = GetWorld()->SpawnActor<ABaseWeapon>(SelectWeapon);
		if (Weapon)
		{
			// 放置在骨骼socket上
			ChangeWeaponAnimSocketName(Weapon, FName("NormalWeaponSocket"));
			// 设置武器归属
			Weapon->SetOwner(this);
		}
	}
}

void APlayerCharacter::AttackDamage()
{
	// Super::AttackDamage();
	// Debug::printLog("player do attackDamage");
	FVector start = this->GetActorLocation();
	FVector end = start + this->GetActorForwardVector() * 200;
	TArray<FHitResult> OutHits;
	TArray<AActor*> ActorsToIgnore;
	ActorsToIgnore.Add(this);
	bool bSphereTraceMultiByProfile = UKismetSystemLibrary::SphereTraceMultiByProfile(
		GetWorld(), start, end, AttackRadius, "",
		true, ActorsToIgnore, EDrawDebugTrace::None, OutHits, true,
		FLinearColor::Blue, FLinearColor::Red, 5.0f);
	TArray<ABaseCharacter*> haveHit;
	if (bSphereTraceMultiByProfile)
	{
		for (FHitResult res : OutHits)
		{
			ABaseCharacter* enemy = Cast<ABaseCharacter>(res.GetActor());
			if (enemy && !haveHit.Contains(enemy))
			{
				enemy->TakeHitDamage(40.0f);
				haveHit.AddUnique(enemy);
			}
		}
	}
}

void APlayerCharacter::TakeHitDamage(const float DamageValue)
{
	Super::TakeHitDamage(DamageValue);
}

void APlayerCharacter::HurtResponse()
{
	float RandRange = FMath::RandRange(0.0f, 1.0f);
	// 播放血屏特效
	GameMode->PlayBloodScreenAnim();
	if (RandRange > 0.5)
	{
		// 执行受伤动画
		PlayMontage(HurtAnimation);
	}
}

void APlayerCharacter::DeathClear()
{
	// 停止控制
	APlayerController* PlayerController = Cast<APlayerController>(Controller);
	if (PlayerController)
	{
		const FInputModeUIOnly uiOnly;
		PlayerController->SetInputMode(uiOnly);
		PlayerController->bShowMouseCursor = true;
		// 停止运动
		GetCharacterMovement()->SetMovementMode(MOVE_None);
	}
	GameMode->MainUI->BossHealthBarPanel->SetVisibility(ESlateVisibility::Hidden);
	GameMode->ChangeToGameOverUI(FText::FromString("Defeat"));
}

void APlayerCharacter::StopOperation()
{
	// 停止控制
	APlayerController* PlayerController = Cast<APlayerController>(Controller);
	if (PlayerController)
	{
		const FInputModeUIOnly uiOnly;
		PlayerController->SetInputMode(uiOnly);
		PlayerController->bShowMouseCursor = true;
		// 停止运动
		GetCharacterMovement()->SetMovementMode(MOVE_None);
	}
}

void APlayerCharacter::StartOperation()
{
	APlayerController* PlayerController = Cast<APlayerController>(Controller);
	if (PlayerController)
	{
		const FInputModeGameAndUI ModeGameAndUI;
		PlayerController->SetInputMode(ModeGameAndUI);
		PlayerController->bShowMouseCursor = false;
		// 停止运动
		GetCharacterMovement()->SetMovementMode(MOVE_Walking);
	}
}

void APlayerCharacter::PlayAttack(const FInputActionValue& Value)
{
	//Debug::printLog("PlayAttackMontage" + IsAttackState);

	if (IsAttackState_Anim)
	{
		SetMovementMode(MOVE_None);
		PlayMontage(AttackMontages[FMath::RandRange(0, 4)]);
		// 动画播放是异步的 要通过动画通知推送事件
	}
}

void APlayerCharacter::GamePause(const FInputActionValue& Value)
{
	// 打开暂停面板 隐藏mainUI
	GameMode->ChangeToGamePauseUI();
}
